/*******************************************************************************
filename      Parser.c
author        Craig Williams
last modified 05-24-08
version       8.0

Description:
  Provides a parser library, as well as several string manipulation funcitons
    to allow for easy parseing of a file. The library handles all file input
    and as much clean up as possiable.

  WARNING: This library heavly uses malloc. The character array returned by
           GrabToken(), PeekToken(), and GrabBytes(<bytes>) must be freeded with
           free(<char *>); manually.

           There are no memory leaks inside the parser library.

  NOTE: Unicode is not supported.

  NOTE: Only Little Endian is supported.

  Parser Functions:
      ParserInit      - Initializer. Takes in a string that contains
                          the file to load, as well as how many bytes to read
                          in from the file at one time (Recommended: 1 KB)
      ParserDeInit    - Frees all the memory used by the parser
      LoadFile        - Opens and loads a new text file into the parser.
      LoadMemory      - Loads a chunk of memory (char *) into the parser for
                          processing. In other words, don't use internal file
                          handleing. NOTE: MEMORY IS COPPIED.
      LoadMemoryLen   - Same as above; however, it takes in the lenght of the
                          memory.
      AddTokenSet     - Adds another Token set. Allows for easy switching
                          between various parseing modes, as well as a built in
                          branching system.
      SetTokenSet     - Changes the current Token Set.
      GetTokenSet     - Returns the current Token Set.
      AddTokenSeparator - Adds a new "Token Separator" to the current token set.
                            A Token Separator is simply the string to check for
                            in the string we are parseing. Depending on the
                            flags you pass in, you can remove this token
                            from being returned from Grab/Peek Token, or do
                            some basic branching.
      AddTokenSep     - Calls the above function, with the default values.
      GrabToken       - Gets the next token from the string, and then updates
                          our position in the string.
      PeekToken       - Gets the next token from the string without updateing
                          our position in the string. All token logic, except
                          for callbacks, is taken into account.
      GrabInt         - Gets the next token from the string, and attempts to
                          convert it to a int. This function handles all
                          required cleanup.
      GrabBinaryInt   - Reads in the next sizeof(int) bytes, and returns them
      GrabFloat       - Gets the next token from the string, and attempts to
                          convert it to a float. This function handles all
                          required cleanup.
      GrabBinaryFloat - Reads in the next sizeof(float) bytes, and returns them
      GrabChar        - Reads in the next byte, and returns it.
      GrabBytes       - Reads in a specific number of bytes from the file, and
                          returns them.
      Seek            - Searches the string for the specified token, and then
                          updates our position in the string, to the character
                          directly following the token.
      SetFilePosition - Changes our location in the file, and reads in the new
                          data, from the specifed location.
      GetFilePosition - Returns the current file position.

      ErrorCode       - Returns the current error code (check defines in
                          parser_core.h).
      PrintErrorCode  - Prints out the Error Code, in a text format to the
                          command prompt.
      End             - Returns 1 if there was a error, or if we reached the end
                          of the file - No more processing possiable.
      GetParserState  - Returns a pointer to the current Parser state.
      SetParserState  - Changes the current Parser state to the specifed state

      GenericDiscard  - Supplied Parser callback, that discards the next token

  Private Parser Functions:
      GrabNextChunk   - Loads in the next chunk of the file. The max amount of
                          memory allocated/the buffer size can be calculated
                          from: BufSize + LongestSep - 1 + 2 * sizeof(int)
      ProcessToken    - Handles the logic of a Separator_str, when ever one is
                          found.
      GrabLeftover    - Retrieves any left over data in SP or from the file when
                          the end of the file is reached.

  String Manipulaiton functions:
      RemoveWhiteSpaces - Removes all white spaces from a string (Space, New
                            Line, Carriage Return, and Tab)
      ToUpper     - Converts all letters in a string to upper case
      ToLower     - Converts all letters in a string to lower case
      Dup         - Creates a copy of the specfied string
      DupLen      - Same as above, but it takes in the length of the string
      DupRange    - Creates a copy of a specific part of a string
      DupRangeFile- Creates a copy of a specific part of a file
      Cmp         - Compairs two strings. If they are equal, 1 is returned. If
                      not, 0 is returned.
*******************************************************************************/
#define _CRT_SECURE_NO_DEPRECATE /* Disable Microsoft deperication warnings   */

#include <stdlib.h>              /* malloc(), realloc(), free(), atoi(), atof */
#include <stdio.h>               /* printf(), fopen(), fclose(), fseek, fread */
#include <string.h>              /* strlen(), memcpy()                        */

#include "OldParser.h"

namespace OldParser
{

#define LOADMEM_DUP   1          /* Make of copy of the memory in LoadMemory? */
#define SEP_OWN_TOKEN 0          /* Should the parser free the token seps?    */
#define SEP_DUP_TOKEN 0          /* Should the token seps be duplicated?      */

struct Separator_str;
struct    Parser_str;

typedef struct Separator_str Separator_str;
typedef struct    Parser_str    Parser_str;

static void GrabNextChunk(void);
static char *GrabLeftover(void);
static char *ProcessToken(struct Separator_str *sep, int *);

static struct Parser_str
{
  Separator_str ***Separator;
  Separator_str  **CurSep   ;

  char *SP        ;           /* Pointer to the actual data to parse          */
  long  SPos      ;           /* Where (index) we last stoped parseing, in SP */
  char *File      ;           /* Name/Path of the file to parse               */
  long  FPos      ;           /* Where we are in the actual file              */
  long  CopyFPos  ;           /* Starting position in the file to copy from   */
  int   CurBufSize;           /* How many characters from the file are in SP  */
  int   ActualSize;           /* Bytes from the file, plus the padding        */
  int   BufSize   ;           /* How many bytes to read in from a file        */
  int   EndOfFile ;           /* Did we find the end of the file?             */
  int   Error     ;           /* Did a error occur?                           */
  int   LongestSep;           /* Longest length of the separator tokens       */

  int   AllocFlag ;           /* Do we need to resize the buffer?             */

  int  *NumOfSeparators;      /* How many Separator_str are in each token set */
  int   NumOfSep       ;      /* Alias for the above.                         */
  int   CurTokenSet    ;      /* Stores the index of the active token set     */
  int   NumOfTokenSet  ;      /* How many token sets there are                */
} *P = 0;

struct Separator_str
{
  char *Token   ;             /* Pointer to the actual token                  */
  int   Return  ;
  int   Ignore  ;
  int   SwitchTo;             /* Which Token Set to use, after token is found */
  int   Len     ;             /* Stores the length of the token               */
  int (*Fun)(void *);         /* Function to call when the token is found     */
  void *Params  ;             /* Paramaters to pass to the callback           */
};

  /* Globals relateing to the String Minipulation functions                   */
static int CaseSensitive = 0; /* Enables or disables Case sensitivity in Cmp()*/

/*******************************************************************************
   Function: ParserInit()

Description: Constructor - Creates our initial Token Set, and sets up some
              default values.

     Inputs: file    - String to the file to load in
             bufsize - How many bytes to read in from the file at a time.

    Outputs: N/A
*******************************************************************************/
void ParserInit(const char *file, int bufsize)
{
  if(P)
    ParserDeInit();

  P = (Parser_str *)malloc(sizeof(Parser_str));

  if(!P){return;}

  if(bufsize <= 0)
    bufsize = 1024;

  P->Separator       =  0      ; /* Pointer Pointer to all our Separator_str  */
  P->CurSep          =  0      ; /* Alias to the Current Separator_str        */
  P->SP              =  0      ; /* The current chunk of data we are parseing */
  P->SPos            =  0      ; /* Our actual position in P->SP              */
  P->File            =  (char *)file   ; /* P->File to open and parse                 */
  P->FPos            =  0      ; /* Our position in the actual file           */
  P->ActualSize      =  0      ; /* How many bytes are actually in the buffer */
  P->CurBufSize      =  0      ; /* Empty buffer                              */
  P->BufSize         =  bufsize; /* Save the requested buffer size            */
  P->EndOfFile       =  0      ; /* Assume we aren't at the end of the file   */
  P->Error           =  0      ; /* No Errors currently exist!                */
  P->NumOfSeparators =  0      ; /* * to our active Token Set separators.     */
  P->NumOfSep        = -1      ; /* No Separator_str exist                    */
  P->CurTokenSet     = -1      ; /* No active Token set is selected           */
  P->NumOfTokenSet   = -1      ; /* No Token Sets exits                       */
  P->LongestSep      =  0      ; /* No seperators, so 0 is the max length     */
  P->CopyFPos        = -1      ; /* -1 siginifes no file fragmentation        */
  P->AllocFlag       =  0      ; /* Don't force a realloc of the buffer       */

  P->Separator       = (Separator_str***)malloc(sizeof(Separator_str**));
  if(!P->Separator){P->Error = PARSER_OUT_OF_MEMORY;return;}
  P->Separator[0]    = (Separator_str **)malloc(sizeof(Separator_str *));
  if(!P->Separator[0]){P->Error = PARSER_OUT_OF_MEMORY;return;}
  P->Separator[0][0] = 0;

  P->NumOfSeparators    = (int *)malloc(sizeof(int));
  if(!P->NumOfSeparators){P->Error = PARSER_OUT_OF_MEMORY;return;}
  P->NumOfSeparators[0] = -1;

  P->CurSep        = P->Separator[0];
  P->CurTokenSet   = 0;
  P->NumOfTokenSet = 0;

  return;
}

/*******************************************************************************
   Function: ParserDeInit()

Description: Destructor - Frees all the data that Parser grabbed.

     Inputs: N/A

    Outputs: N/A
*******************************************************************************/
void ParserDeInit(void)
{
  int i, j;

  if(P)
  {
    if(P->SP)
      free(P->SP);

    for(i = 0; i <= P->NumOfTokenSet; ++i)
      if(P->Separator[i])
      {
        for(j = 0; j <= P->NumOfSeparators[i]; ++j)
          if(P->Separator[i][j])
          {
            #if (SEP_OWN_TOKEN || SEP_DUP_TOKEN)
              free(P->Separator[i][j]->Token);
            #endif

            free(P->Separator[i][j]);
          }

        free(P->Separator[i]);
      }

    if(P->Separator)
      free((void *)P->Separator);

    if(P->NumOfSeparators)
      free((void *)P->NumOfSeparators);

    free(P);

    P = 0;
  }

  return;
}

/*******************************************************************************
   Function: GrabNextChunk()

Description: Grabs the next chunk of data from the file. If some data was
                left in P->SP, it will be preserved.

     Inputs: N/A

    Outputs: N/A - Updates P->SP to contain the next chunk of data.
*******************************************************************************/
void GrabNextChunk(void)
{
  int   len;
  FILE *fp ;
  char *sp ;

  if(!P->File){P->Error = PARSER_COULD_NOT_OPEN_FILE;return;}

  if(P->EndOfFile){P->Error = PARSER_END_OF_FILE;return;}

  if(!P->SP || P->AllocFlag)
  {
    if(!P->SP)
      P->SP = (char *)malloc(sizeof(char) * P->BufSize + P->LongestSep + 1);
    else
      P->SP = (char *)realloc(P->SP, sizeof(char) * P->BufSize+P->LongestSep+1);

    P->AllocFlag = 0;

    if(!P->SP){P->Error = PARSER_OUT_OF_MEMORY; return;}
  }

  sp  = P->SP;

  len = P->ActualSize - P->SPos;

  if(len >= P->LongestSep && P->LongestSep)
  {
    if(P->CopyFPos == -1)
      P->CopyFPos = P->FPos - P->ActualSize + P->SPos;

    len = P->LongestSep - 1;

    memcpy(sp, sp + P->ActualSize - len, len);
  }
  else
    memcpy(sp, sp + P->ActualSize - len, len);

  sp += len;

  fp = fopen(P->File, "rb");

  if(!fp){P->Error = PARSER_COULD_NOT_OPEN_FILE;return;}

  fseek(fp, P->FPos, 0);
  P->CurBufSize = (int)fread(sp, 1, P->BufSize, fp);
  fclose(fp);

  sp[P->CurBufSize] = 0;

  P->FPos += P->CurBufSize;

  P->SPos = 0;

  P->ActualSize = P->CurBufSize + len;

  if(!P->CurBufSize || P->CurBufSize < P->BufSize)
  {
    P->EndOfFile = 1;
    P->CurBufSize = P->ActualSize;
  }
  else
  if(P->ActualSize < P->LongestSep)
    P->CurBufSize -= P->LongestSep;

  return;
}

/*******************************************************************************
   Function: AddTokenSet()

Description: Adds a new Token Set for the GrabToken function to use

     Inputs: N/A

    Outputs: -1 - Error occured
             0+ - Index of the new Token Set
*******************************************************************************/
int AddTokenSet(void)
{
  if(!P)
    return -1;

  P->NumOfTokenSet++;

  P->Separator = (Separator_str ***)
       realloc(P->Separator, sizeof(Separator_str **) * (P->NumOfTokenSet + 1));

  if(!P->Separator){P->Error = PARSER_OUT_OF_MEMORY;return -1;}

  P->Separator[P->NumOfTokenSet] = (Separator_str **)
       malloc(sizeof(Separator_str *));

  if(!P->Separator[P->NumOfTokenSet]){P->Error= PARSER_OUT_OF_MEMORY;return -1;}

  P->NumOfSeparators = (int *)
       realloc(P->NumOfSeparators, sizeof(int)*(P->NumOfTokenSet + 1));

  if(!P->NumOfSeparators){P->Error = PARSER_OUT_OF_MEMORY;return -1;}

  P->NumOfSeparators[P->NumOfTokenSet] = -1;

  P->CurSep      = P->Separator[P->NumOfTokenSet];
  P->NumOfSep    = P->NumOfSeparators[P->NumOfTokenSet];
  P->CurTokenSet = P->NumOfTokenSet;

  return P->NumOfTokenSet;
}

/*******************************************************************************
   Function: SetTokenSet()

Description: Changes the current token set used with GrabToken & such

     Inputs: TokenSet - Index of the desiered Token Set

    Outputs: -1 - Invalid Token Set
             0+ - Current Token Set being used
*******************************************************************************/
int SetTokenSet(int tokenset)
{
  if(!P || tokenset > P->NumOfTokenSet || tokenset < 0)
    return -1;

  P->CurTokenSet = tokenset;
  P->CurSep      = P->Separator[tokenset];
  P->NumOfSep    = P->NumOfSeparators[tokenset];

  return tokenset;
}

/*******************************************************************************
   Function: GetTokenSet()

Description: Returns the current token set.

     Inputs: N/A

    Outputs: Current TokenSet
*******************************************************************************/
int GetTokenSet(void)
{
  return P->CurTokenSet;
}

/*******************************************************************************
   Function: AddTokenSeparator()

Description: Adds a new character to the current array of token separators.

     Inputs: sp       - Pointer to the string to consider as a separator
             Return   - Should the separator be returned by Grab/PeekToken()?
                        This is useful for filtering out specific strings.
             switchto - Automatically switch to the specifed token set, when the
                        token is found.
             ignore   - If this Token is found, just keep going. Orignally
                        designed to be used with strings. For example,
                        \" should be ignored; however, " will be picked out
                        if we don't ignore \"
             fun      - Callback function to call when ever the token is found.
             params   - Paramaters to pass to the callback

    Outputs: 0 - Specifed token is not valid
             1 - Token added
*******************************************************************************/
int AddTokenSeparator(const char *sp, char Return, signed char switchto, char ignore,
                      int (*fun)(), void *params)
{
  int len;
  Separator_str *sep;

  if(!P || !sp || !sp[0])
    return 0;

  P->NumOfSeparators[P->CurTokenSet]++;
  P->NumOfSep = P->NumOfSeparators[P->CurTokenSet];

  if(P->Separator[P->CurTokenSet] == 0)
    P->Separator[P->CurTokenSet] = (Separator_str **)malloc(sizeof(Separator_str *) * (P->NumOfSep + 1));
  else
    P->Separator[P->CurTokenSet] = (Separator_str **)realloc(P->Separator[P->CurTokenSet], sizeof(Separator_str *) * (P->NumOfSep + 1));

  if(!P->Separator[P->CurTokenSet]){P->Error = PARSER_OUT_OF_MEMORY;return -1;}

  P->Separator[P->CurTokenSet][P->NumOfSep] = (Separator_str *)malloc(sizeof(Separator_str));

  if(!P->Separator[P->CurTokenSet][P->NumOfSep]){P->Error = PARSER_OUT_OF_MEMORY;return -1;}

  P->CurSep = P->Separator[P->CurTokenSet];

  len = strlen(sp);

  sep = P->CurSep[P->NumOfSep];

  #if SEP_DUP_TOKEN
    sep->Token  = DupLen(sp, len);
  #else
    sep->Token  = (char *)sp;
  #endif
  sep->SwitchTo = switchto;
  sep->Len      = len;
  sep->Fun      = (PARSER_CALLBACK)fun;
  sep->Params   = params;

  sep->Return   = Return;
  sep->Ignore   = ignore;

  if(len > P->LongestSep)
  {
    P->LongestSep = len;
    P->AllocFlag  = 1;
  }

  return 1;
}

/*******************************************************************************
   Function: AddTokenSep()

Description: Adds a new character to the current array of token separators. This
               function is a wrapper for the above function. It defaults to the
               standard behaviors
                 Return   -  1 - The token separator will be returned
                 switchto - -1 - Don't change the token set
                 ignore   -  0 - Don't ignore the token
                 fun      -  0 - Don't call a callback function
                 params   -  0 - No params

     Inputs: sp - Pointer to the string to consider as a separator

    Outputs: 0 - Specifed token is not valid
             1 - Token added
*******************************************************************************/
int AddTokenSep(const char *sp)
{
  return AddTokenSeparator(sp, 1, -1, 0, 0, 0);
}

/*******************************************************************************
   Function: GrabToken()

Description: Grabs the next token in the character array

     Inputs: N/A

    Outputs: 0 - no valid Token Separators are present
             Pointer to a new character array containing the token
*******************************************************************************/
char *GrabToken(void)
{
  int   spos  ;       /* Tracks the Character in SP we are checking           */
  int   sepnum;       /* Tracks the current Separator Token to check          */
  char *buffer;       /* Char * that stores the string we will return         */
  char *token;

  if(!P || P->Error || P->NumOfSep < 0)
    return 0;

  for(; !P->Error; GrabNextChunk())
    for(spos = P->SPos; spos < P->CurBufSize; ++spos)
      for(sepnum = 0; sepnum <= P->NumOfSep; ++sepnum)
      {
        token  = P->CurSep[sepnum]->Token;
        buffer = P->SP + spos;
        while(*token && *buffer == *token){++buffer;++token;}

        if(*token)
          continue;

        if((buffer = ProcessToken(P->CurSep[sepnum], &spos)) == 0)
        {
          sepnum = -1;                               /* CHANGE: SEEK ALTERNATI*/
          if(spos <= P->CurBufSize && P->CurBufSize) /* && P->CurBufSize      */
            continue;                                /*   Corects incorrect   */
          else                                       /*   Parsing at end of   */
            break;                                   /*   File.               */
        }

        return buffer;
      }

  return GrabLeftover();
}

/*******************************************************************************
   Function: ProcessToken()

Description: Handles a Token Sepeator when ever one is found.

     Inputs: *sep      - Pointer to the Separator_str that was found.
             *spos     - Position in the string where the separator was found.
                           This function will most likely update the position in
                           the string.

    Outputs: 0  - GrabToken() should not return anything. Search for the next
                  token.
             1+ - Pointer to the token to return.
*******************************************************************************/
char *ProcessToken(Separator_str *sep, int *spos)
{
  char *buffer = 0;

  if(sep->Ignore)
  {
    *spos += sep->Len;

      /* Prevent a callback from calling GrabToken(), since it will start a   *
       *   infinate loop. Also, GetFilePostion() won't be right.              */
    P->Error = PARSER_GRAB_TOKEN_IGNORE;
    if(sep->Fun)
      (*sep->Fun)(sep->Params);     /* Deref is required for DeSmet C support */
    P->Error = 0;
  }
  else
  if(*spos == P->SPos && P->CopyFPos == -1)
  {
    P->SPos += sep->Len;

    SetTokenSet(sep->SwitchTo);

    if(sep->Fun)
    {
      if((*sep->Fun)(sep->Params))  /* Deref is required for DeSmet C support */
        if(sep->Return)
          buffer = DupLen(sep->Token, sep->Len);

      *spos = P->SPos;
    }
    else
    if(sep->Return)
      buffer = DupLen(sep->Token, sep->Len);
    else
      *spos = P->SPos;
  }
  else
  {
    if(P->CopyFPos == -1)
      buffer = DupRange(P->SP, P->SPos, *spos);
    else
    {
      buffer = DupRangeFile(P->File, P->CopyFPos, P->FPos + *spos - P->ActualSize);
      P->CopyFPos = -1;
    }

    P->SPos = *spos;
  }

  return buffer;
}

/*******************************************************************************
   Function: GrabLeftover()

Description: Returns any left over data in the file

     Inputs: N/A

    Outputs: 0  - No data is left in SP or the file.
             1+ - Pointer to the token.
*******************************************************************************/
char *GrabLeftover(void)
{
  char *buffer = 0;

  if(!P->ActualSize && P->CopyFPos == -1)
    return 0;

  if(P->CopyFPos != -1)
    buffer = DupRangeFile(P->File, P->CopyFPos, P->FPos);
  else
  if(P->SP)
    buffer = DupRange(P->SP, P->SPos, P->ActualSize);

  if(buffer && buffer[0] == 0)
  {
    free(buffer);
    buffer = 0;
  }

  P->CopyFPos   = -1;
  P->CurBufSize =  0;
  P->ActualSize =  0;
  P->SPos       =  0;

  return buffer;
}

/*******************************************************************************
   Function: PeekToken()

Description: Grabs the next token in the character array, while preserveing
               our current position in the string. All logic except for
               callbacks are taken into account.

             This is just a bastard copy of GrabToken(). It was not worth
               the drop in performance to add a variable, so copy & paste
               was used.

     Inputs: N/A

    Outputs: Char * to the next token
*******************************************************************************/
char *PeekToken(void)
{
  long  fpos    ;     /* Stores the original absolute file position           */
  long  oFPos   ;     /* Stores the original file position                    */
  int   ospos   ;     /* Stores the original string position                  */
  int   tokenset;     /* Stores the original token set                        */

  int   spos = 0;     /* Tracks the Character in SP we are checking           */
  int   sepnum  ;     /* Tracks the current Separator Token to check          */
  char *buffer  ;     /* Char * that stores the string we will return         */
  char *token   ;

  Separator_str sep;

  if(!P || P->Error || P->NumOfSep < 0)
    return 0;

  fpos     = GetFilePosition();
  oFPos    = P->FPos;
  ospos    = P->SPos;
  tokenset = P->CurTokenSet;

  for(; !P->Error; GrabNextChunk())
    for(spos = P->SPos; spos < P->CurBufSize; ++spos)
      for(sepnum = 0; sepnum <= P->NumOfSep; ++sepnum)
      {
        token  = P->CurSep[sepnum]->Token;
        buffer = P->SP + spos;
        while(*token && *buffer == *token){++buffer; ++token;}

        if(*token)
          continue;

          /* Only disable the function callback */
        sep = *P->CurSep[sepnum];
        sep.Fun = 0;

        if((buffer = ProcessToken(&sep, &spos)) == 0)
        {
          sepnum = -1;
          if(spos <= P->CurBufSize)
            continue;
          else
            break;
        }

        if(oFPos == P->FPos && !P->Error)
          P->SPos = ospos;
        else
          SetFilePosition(fpos);

        if(tokenset != P->CurTokenSet)
          SetTokenSet(tokenset);

        return buffer;
      }

  buffer = GrabLeftover();

  if(oFPos == P->FPos && !P->Error)
    P->SPos = spos;
  else
    SetFilePosition(fpos);

  if(tokenset != P->CurTokenSet)
    SetTokenSet(tokenset);

  return buffer;
}

/*******************************************************************************
   Function: GrabInt()

Description: Grabs the next token in the character array, convert it to a int
               and then return the new int

     Inputs: N/A

    Outputs: The next token converted to a int
*******************************************************************************/
int GrabInt(void)
{
  int rint;
  char *token;

  if(!P)
    return 0;

  if((token = GrabToken()) == 0)
    return 0;

  rint = atoi(token);

  free(token);

  return rint;
}

/*******************************************************************************
   Function: GrabBinaryInt()

Description: Grabs the next sizeof(int), and convert it to a int

     Inputs: N/A

    Outputs: the next sizeof(int), as a int
*******************************************************************************/
int GrabBinaryInt(void)
{
  int *rint;

  if(!P)
    return 0;

  if(P->SPos + sizeof(int) > (unsigned int)P->ActualSize)
    SetFilePosition(GetFilePosition());

  if(sizeof(int) > (unsigned int)P->ActualSize)
  {
    P->SPos   = P->ActualSize;
    P->Error  = PARSER_END_OF_FILE;
    return   0;
  }

  rint = (int *)((char *)P->SP + P->SPos);

  P->SPos += sizeof(int);

  return *rint;
}

/*******************************************************************************
   Function: GrabFloat()

Description: Grabs the next token in the character array, convert it to a float
              and then returns the new float

     Inputs: N/A

    Outputs: The next token converted to a float
*******************************************************************************/
float GrabFloat(void)
{
  float rfloat;
  char *token;

  if(!P)
    return 0;

  if((token = GrabToken()) == 0)
    return 0.0f;

  rfloat = (float)atof(token);

  free(token);

  return rfloat;
}

/*******************************************************************************
   Function: GrabBinaryFloat()

Description: Grabs the next sizeof(float) bytes, and return it as a float

     Inputs: N/A

    Outputs: The next sizeof(float) as a float
*******************************************************************************/
float GrabBinaryFloat(void)
{
  float *rfloat;

  if(!P)
    return 0.0f;

  if(P->SPos + sizeof(float) > (unsigned int)P->ActualSize)
    SetFilePosition(GetFilePosition());

  if(sizeof(float) > (unsigned int)P->ActualSize)
  {
    P->SPos   = P->ActualSize;
    P->Error  = PARSER_END_OF_FILE;
    return  0.0f;
  }

  rfloat = (float *)(P->SP + P->SPos);

  P->SPos += sizeof(float);

  return *rfloat;
}

/*******************************************************************************
   Function: GrabChar()

Description: Grabs the next char from the string.

     Inputs: N/A

    Outputs: The next char from the string
*******************************************************************************/
char GrabChar(void)
{
  char *rchar;

  if(!P)
    return 0;

  if(P->SPos + sizeof(char) > (unsigned int)P->ActualSize)
    SetFilePosition(GetFilePosition());

  if(1 > P->ActualSize)
  {
    P->SPos   = P->ActualSize;
    P->Error  = PARSER_END_OF_FILE;
    return 0;
  }

  rchar = P->SP + P->SPos;

  P->SPos += sizeof(char);

  return *rchar;
}

/*******************************************************************************
   Function: GrabBytes()

Description: Grabs the specifed number of bytes from the file.

             Note: The specifed buffer size (P->BufSize) must be larger then the
                     requested number of bytes. If not, then a error will be
                     generated.

     Inputs: bytes - How many bytes to read in from the file

    Outputs: The specifed number of bytes
*******************************************************************************/
char *GrabBytes(int bytes)
{
  char *ret;
  int i;

  if(!P || bytes <= 0)
    return 0;

  if(P->SPos + bytes > P->ActualSize)
    SetFilePosition(GetFilePosition());

  if(bytes > P->ActualSize)
  {
    P->SPos  = P->ActualSize;
    P->Error = PARSER_END_OF_FILE;
    return  0;
  }

  ret = (char *)malloc(sizeof(char) * (bytes + 1));

  for(i = 0; i < bytes; ++i)
   ret[i] = P->SP[i + P->SPos];

  P->SPos += bytes;

  return ret;
}

/*******************************************************************************
   Function: Seek()

Description: Search through the array, until we find the specifed Token, and
               then update our position in the character array

     Inputs: *serach - Token to serach for in the character array

    Outputs: 0 - The specified Token could not be found. Pos was not updated.
             1 - Token found. Updated position to character after the token
*******************************************************************************/
int Seek(const char *search)
{
  int   i;
  int   k;
  int len  = strlen(search);
  int fpos = GetFilePosition();

  if(!P || len < 0 || P->NumOfSep < 0)
    return 0;

  while(!P->Error)
  {
    for(i = P->SPos; i < P->ActualSize; ++i)
      if(P->SP[i] == search[0])
      {
        for(k = 0; k < len; ++k)
          if(P->SP[i + k] != search[k])
            break;

        if(k != len)
          continue;

        P->SPos = i + len;
        P->CopyFPos = -1;

        return 1;
      }

    if(!P->File)
      return 0;

    GrabNextChunk();
  }

  SetFilePosition(fpos);

  return 0;
}

/*******************************************************************************
   Function: SetFilePosition()

Description: Changes the current file position (in bytes), and then attempts
               to read in the data.

     Inputs: fpos - Requested poisition in the file.

    Outputs: 1 - File position updated, and no errors were found
             0 - Error occured, or you requested a bad file position.
*******************************************************************************/
int SetFilePosition(long fpos)
{
  if(!P || fpos < 0)
    return 0;

  P->FPos       = fpos;
  P->SPos       =  0  ;
  P->Error      =  0  ;
  P->EndOfFile  =  0  ;
  P->CurBufSize =  0  ;
  P->ActualSize =  0  ;
  P->CopyFPos   = -1  ;

  GrabNextChunk();

  return !End();
}

/*******************************************************************************
   Function: GetFilePosition()

Description: Gets the current file position

     Inputs: N/A

    Outputs: Current position in the file
*******************************************************************************/
long GetFilePosition(void)
{
  if(!P)
    return 0;

  return P->FPos + P->SPos - P->ActualSize;
}

/*******************************************************************************
   Function: LoadMemory()

Description: Loads a chunk of memory into the parser library, instead of useing
               the built in file handleing. Note: memory is coppied into P->SP.
               You should free memory afterwards, if you don't need it.

     Inputs: memory - Pointer to the memory to process

    Outputs: 1 - Memory looks valid.
             0 - Memory is not valid.
*******************************************************************************/
int LoadMemory(const char *memory)
{
  if(!memory)
    return 0;

  return LoadMemoryLen(memory, strlen(memory)); /* We can ignore the NULL term*/
}

/*******************************************************************************
   Function: LoadMemoryLen()

Description: Loads a chunk of memory into the parser library, instead of useing
               the built in file handleing. Note: memory is coppied into P->SP.
               You should free memory afterwards, if you don't need it.

     Inputs: mem - Pointer to the memory to process
             len - Length (bytes) of the memory

    Outputs: 1 - Memory looks valid.
             0 - Memory is not valid.
*******************************************************************************/
int LoadMemoryLen(const char *mem, int len)
{
  if(!P)
    return 0;

  if(!mem || !len)
  {
    P->Error = PARSER_MEMORY_NOT_VALID;
    return 0;
  }

  if(P->SP)
    free(P->SP);

  #if LOADMEM_DUP
    P->SP = DupRange(mem, 0, len);
  #else
    P->SP = mem;
  #endif

  P->CurBufSize = len;
  P->ActualSize = len;
  P->File       =  0;
  P->FPos       =  0;
  P->CopyFPos   = -1;
  P->SPos       =  0;
  P->Error      =  0;
  P->EndOfFile  =  1;

  return 1;
}

/*******************************************************************************
   Function: LoadFile()

Description: Loads a new file into the parser.

     Inputs: *file - Name of the file to open and parse.

    Outputs: 1 - File sucessfully loaded!
             0 - Error occured.
*******************************************************************************/
int LoadFile(const char *file)
{
  if(!P)
    return 0;

  P->SPos       =  0;
  P->File       = (char *)file;
  P->FPos       =  0;
  P->CopyFPos   = -1;
  P->CurBufSize =  0;
  P->ActualSize =  0;
  P->EndOfFile  =  0;
  P->Error      =  0;

  return 1;
}

/*******************************************************************************
   Function: ErrorCode()

Description: Grabs the specifed number of bytes from the file

     Inputs: N/A

    Outputs: The specifed number of bytes
*******************************************************************************/
int ErrorCode(void)
{
  if(!P)
    return PARSER_NOT_INITIALIZED;

  return P->Error;
}

/*******************************************************************************
   Function: PrintErrorCode()

Description: Prints out the error code, to the command prompt

     Inputs: N/A

    Outputs: N/A
*******************************************************************************/
void PrintErrorCode(void)
{
  if(!P)
    printf("%s: Parser was not initialized.", __FILE__);
  else
    switch(P->Error)
    {
      case 0:
        if(P->SPos == P->ActualSize)
          printf("%s: Reached the end of %s\n", __FILE__, P->File);
        else
          printf("%s: No errors\n", __FILE__);
        break;
      case PARSER_COULD_NOT_OPEN_FILE:
        if(P->File)
          printf("%s: Could not open |%s|\n", __FILE__, P->File);
        else
          printf("%s: No file was specifed.\n", __FILE__);
        break;
      case PARSER_OUT_OF_MEMORY:
        printf("%s: Memory Allocation failed.\n", __FILE__);
        break;
      case PARSER_END_OF_FILE:
        printf("%s: Reached the end of %s\n", __FILE__, P->File);
        break;
      case PARSER_MEMORY_NOT_VALID:
        printf("%s: Memory fed into LoadMemory wasn't valid\n", __FILE__);
        break;
      case PARSER_GRAB_TOKEN_IGNORE:
        printf("%s: GrabToken() was called from a callback attached to a token with Ignore set to true. This is not supported.\n", __FILE__);
        break;
    };
}

/*******************************************************************************
   Function: End()

Description: Returns 1 if we are at the end of the file

     Inputs: N/A

    Outputs: 1 - We reached the end of the file
             0 - We still have data to process
*******************************************************************************/
int End(void)
{
  if(!P || P->Error || !P->SP)
    return 1;

  return 0;
}

/*******************************************************************************
   Function: GetParserState()

Description: Returns a pointer to the current Parser state.

     Inputs: N/A

    Outputs: Pointer to the current Parser state
*******************************************************************************/
void *GetParserState(void)
{
  return P;
}

/*******************************************************************************
   Function: SetParserState()

Description: Overwrites the current Parser state with the specifed state. This
               is useful to restore a previous state or to create another.

     Inputs: *state - State to set the Parser to use

    Outputs: N/A
*******************************************************************************/
void SetParserState(void *state)
{
  P = (Parser_str *)state;
}


int ParserMemoryUsage(void)
{
  int size = 0;
  int tset;

  if(!P)
    return 0;

    // P is valid, so we allocated at least 1 of them
  size += sizeof(Parser_str);
    // Number of bytes P->SP can hold
  size += P->BufSize + P->LongestSep + 1;
    // P->NumOfSeparators (array of ints)
  size += sizeof(int) * (P->NumOfTokenSet + 1);
    // P->Separator (array of pointers to pointers)
  size += sizeof(Separator_str  **) * (P->NumOfTokenSet + 1);

  for(tset = 0; tset <= P->NumOfTokenSet; ++tset)
  {
      // P->Separator[tset] (array of pointers to Separator_str)
    size += sizeof(Separator_str *) * (P->NumOfSeparators[tset] + 1);
      // Memory allocated for each Separator_str
    size += sizeof(Separator_str  ) * (P->NumOfSeparators[tset] + 1);
    #if (SEP_OWN_TOKEN || SEP_DUP_TOKEN)
        // Add the number of bytes each token string occupies
      for(sep = 0; sep <= P->NumOfSeparators[tset]; ++sep)
        size += P->Separator[tset][sep]->Len + 1;
    #endif
  }

  return size;
}

/*******************************************************************************
   Function: GenericDiscard()

Description: Generic Parser callback designed to discard the next token. This
               is useful for removeing comments and such.

     Inputs: *state - State to set the Parser to use

    Outputs: 0 - Don't return the token to the original funciton that called
                   GrabToken()
*******************************************************************************/
int GenericDiscard(void *unused)
{
  unused = (char *)GrabToken();
  if(unused)
    free(unused);
  return 0;
}

/*******************************************************************************
 *                      -- End of Parser library --                            *
 *                                                                             *
 * The following functions are just generic string minipulations functions     *
 * that are not aviable in the standard library, or opperate on different      *
 * principles.                                                                 *
 ******************************************************************************/


/*******************************************************************************
   Function: RemoveWhiteSpaces()

Description: Removes all white spaces from a character array.
             White Spaces: Space
                           Tab
                           Return

             Procedure:
                Walk the array until we find the null terminator. If the current
                position contains a non null character, move it to the next
                valid position in the array. Once we find a white space
                character, we just move to the next character in the array.

     Inputs: *P->SP - Pointer to the string array to modify

    Outputs: -1 - Specifed string isn't valid
             New length of the array/position of null terminator
*******************************************************************************/
int RemoveWhiteSpaces(char *sp)
{
  register int i;   /* Current position we are checking for white space       */
  register int pos; /* Where we will store the next non white space character */

  if(!sp)
    return -1;

  for(i = 0, pos = 0; sp[i]; ++i)
    switch(sp[i])
    {
      case ' ' :    /* Space                                                  */
      case '\n':    /* new line                                               */
      case '\r':    /* carriage return                                        */
      case '\t':    /* Tab                                                    */
        break;
      default:
        sp[pos++] = sp[i];
        break;
    };

  sp[pos] = 0;      /* Mark the new end position of the character array       */

  return pos;
}

/*******************************************************************************
   Function: ToUpper()

Description: Makes every character in an array upper case

     Inputs: *P->SP - Array of characters to upper case

    Outputs: N/A
*******************************************************************************/
void ToUpper(char *sp)
{
  register int i;

  if(!sp)
    return;

  for(i = 0; sp[i]; ++i)
    if(sp[i] >= 'a' && sp[i] <= 'z')
      sp[i] = (char)(sp[i] + ('A' - 'a')); /* Prevents Borland Warning        */
}

/*******************************************************************************
   Function: ToLower()

Description: Makes every character in an array lower case

     Inputs: *P->SP - Array of characters to lower case

    Outputs: N/A
*******************************************************************************/
void ToLower(char *sp)
{
  register int i;

  if(!sp)
    return;

  for(i = 0; sp[i]; ++i)
    if(sp[i] >= 'A' && sp[i] <= 'Z')
      sp[i] = (char)(sp[i] + ('a' - 'A')); /* Prevents Borland Warning        */
}

/*******************************************************************************
   Function: Dup()

Description: Takes in a string, and creates a duplicate of it

     Inputs: *sp - pointer to the string to duplicate

    Outputs: pointer to a copy of the string
*******************************************************************************/
char *Dup(const char *sp)
{
  return DupLen(sp, strlen(sp));
}

/*******************************************************************************
   Function: DupLen()

Description: Takes in a string, and creates a duplicate of it

     Inputs: *sp  - pointer to the string to duplicate
              len - Length of the string. The null terminator is automatically
                      attached. IE, you can juse use strlen(sp)

    Outputs: pointer to a copy of the string
*******************************************************************************/
char *DupLen(const char *sp, int len)
{
  char *buffer;

  if(!len)
    return 0;

  if((buffer = (char *)malloc(sizeof(char) * ++len)) == 0)
    return 0;

  memcpy(buffer, sp, len);

  return buffer;
}

/*******************************************************************************
   Function: DupRange()

Description: Duplicates a specifec part of a string

     Inputs: *P->SP   - String to copy the data from
             start - Where in the start to copy data from
             end   - Where to stop copying data

    Outputs: Pointer to the copy of the specifed part of the string
*******************************************************************************/
char *DupRange(const char *sp, int start, int end)
{
  int len = end - start;
  char *buffer;

  if(!sp)
    return 0;

  if((buffer = (char *)malloc(sizeof(char) * (len + 1))) == 0)
    return 0;

  memcpy(buffer, sp + start, len);
  buffer[len] = 0;

  return buffer;
}

/*******************************************************************************
   Function: DupRangeFile()

Description: Duplicates a specifec part of a file

     Inputs: *file  - Name of the file to copy data from
              start - Where in the start to copy data from
              end   - Where to stop copying data

    Outputs: Pointer to the copy of the specifed part of the string
*******************************************************************************/
char *DupRangeFile(const char *file, int start, int end)
{
  int   len = end - start;
  char *buffer;
  FILE *fp    ;

  if(!file)
    return 0;

  if((fp = fopen(file, "rb")) == 0)
    return 0;

  if((buffer = (char *)malloc(sizeof(char) * (len + 1))) == 0)
  {
    fclose(fp);
    return 0;
  }

  fseek(fp, start, 0);
  fread(buffer, 1, len, fp);
  fclose(fp);

  buffer[len] = 0;

  return buffer;
}

/*******************************************************************************
   Function: Cmp()

Description: Compaires two strings. If CaseSensitive is set to 0, all white
               spaces are removed, and then all characters are converted to
               lower case.

     Inputs: *osp  - First String to compare
             *osp2 - Second string to compaire

    Outputs: 1 - Strings are the same
             0 - Strings are not the same
*******************************************************************************/
char Cmp(const char *osp, const char *osp2)
{
  int i = 0;
  char *sp, *sp2;

  if(!osp || !osp2)
    return 0;

  if(!CaseSensitive)
  {
    sp  = Dup(osp);
    sp2 = Dup(osp2);

    if(RemoveWhiteSpaces(sp) != RemoveWhiteSpaces(sp2))
    {
      free(sp);
      free(sp2);
      return 0;
    }

    ToLower(sp);
    ToLower(sp2);
  }
  else
  {
    sp  = (char *)osp;
    sp2 = (char *)osp2;
  }

  while(sp[i] && sp[i] == sp2[i]) ++i;

  if(sp[i])
    i = 0;
  else
    i = 1;

  if(!CaseSensitive)
  {
    free(sp);
    free(sp2);
  }

  return (char)i;
}

}
